package com.example.web_playback

import android.content.Context
import android.os.Environment
import android.util.Log
import kotlinx.coroutines.*
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URL
import java.security.MessageDigest

class ResourceDownloadManager(private val context: Context) {
    
    companion object {
        private const val TAG = "ResourceDownloadManager"
        private const val BASE_URL = "http://172.16.0.39:3000/static" // 物理机调试地址
        private const val CACHE_DIR = "web_resources"
        private const val VERSION_FILE = "version.json"
    }
    
    private val cacheDir = File(context.getExternalFilesDir(null), CACHE_DIR)
    private val downloadScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
    
    // 资源目录列表 - 需要递归下载整个目录
    val resourceDirectories = listOf(
        "SolarPower",
        "VoiceInteractiveMap", 
        "TurbofanEngine",
        "Hannault",
        "KimAqQarav",
        "Lightnin_Glow",
        "Crooks_Radiometer",
        "Manipulator",
        "Remote_Piano",
        "Fun_Beginner_AI",
        "Specimen_Wheat",
        "Specimen_Soil",
        "Specimen_Silkworm",
        "Specimen_Dragonfly",
        "Specimens_FoodCrops",
        "Specimens_Arthropods",
        "specimen_beanSprouts",
        "Specimens_Minerals",
        "specimen_fossil"
    )
    
    // 主HTML文件映射（用于获取本地路径）
    private val mainHtmlFiles = mapOf(
        "SolarPower" to "SolarPower/SolarPower.html",
        "VoiceInteractiveMap" to "VoiceInteractiveMap/VoiceInteractiveMap.html",
        "TurbofanEngine" to "TurbofanEngine/TurbofanEngine.html",
        "Hannault" to "Hannault/index.html",
        "KimAqQarav" to "KimAqQarav/index.html",
        "Lightnin_Glow" to "Lightnin_Glow/index.html",
        "Crooks_Radiometer" to "Crooks_Radiometer/index.html",
        "Manipulator" to "Manipulator/index.html",
        "Remote_Piano" to "Remote_Piano/index.html",
        "Fun_Beginner_AI" to "Fun_Beginner_AI/index.html",
        "Specimen_Wheat" to "Specimen_Wheat/index.html",
        "Specimen_Soil" to "Specimen_Soil/index.html",
        "Specimen_Silkworm" to "Specimen_Silkworm/index.html",
        "Specimen_Dragonfly" to "Specimen_Dragonfly/index.html",
        "Specimens_FoodCrops" to "Specimens_FoodCrops/index.html",
        "Specimens_Arthropods" to "Specimens_Arthropods/index.html",
        "specimen_beanSprouts" to "specimen_beanSprouts/index.html",
        "Specimens_Minerals" to "Specimens_Minerals/index.html",
        "specimen_fossil" to "specimen_fossil/index.html"
    )
    
    interface DownloadCallback {
        fun onProgress(progress: Int, total: Int)
        fun onComplete()
        fun onError(error: String)
    }
    
    init {
        // 确保缓存目录存在
        if (!cacheDir.exists()) {
            cacheDir.mkdirs()
        }
    }
    
    /**
     * 检查资源是否需要更新
     */
    suspend fun checkForUpdates(): Boolean {
        return try {
            val versionUrl = URL("$BASE_URL$VERSION_FILE")
            val connection = versionUrl.openConnection() as HttpURLConnection
            connection.requestMethod = "GET"
            connection.connectTimeout = 10000
            connection.readTimeout = 15000
            
            val responseCode = connection.responseCode
            if (responseCode == HttpURLConnection.HTTP_OK) {
                val inputStream = connection.inputStream
                val versionContent = inputStream.bufferedReader().use { it.readText() }
                inputStream.close()
                connection.disconnect()
                
                // 这里可以解析版本信息，比较本地版本
                // 简化处理：总是检查更新
                true
            } else {
                false
            }
        } catch (e: Exception) {
            Log.e(TAG, "检查更新失败", e)
            false
        }
    }
    
    /**
     * 下载所有资源（递归下载整个目录）
     */
    fun downloadAllResources(callback: DownloadCallback) {
        downloadScope.launch {
            try {
                val totalDirectories = resourceDirectories.size
                var completedDirectories = 0
                val failedDirectories = mutableListOf<String>()
                
                Log.d(TAG, "开始下载所有资源，共 $totalDirectories 个目录")
                callback.onProgress(0, totalDirectories)
                
                resourceDirectories.forEach { directoryName ->
                    try {
                        Log.d(TAG, "开始下载目录: $directoryName")
                        val success = downloadDirectory(directoryName)
                        if (success) {
                            completedDirectories++
                            Log.d(TAG, "目录下载成功: $directoryName ($completedDirectories/$totalDirectories)")
                            callback.onProgress(completedDirectories, totalDirectories)
                        } else {
                            failedDirectories.add(directoryName)
                            Log.e(TAG, "目录下载失败: $directoryName")
                        }
                    } catch (e: Exception) {
                        failedDirectories.add(directoryName)
                        Log.e(TAG, "下载目录异常: $directoryName", e)
                    }
                }
                
                Log.d(TAG, "下载完成统计: 成功=$completedDirectories, 失败=${failedDirectories.size}")
                if (failedDirectories.isNotEmpty()) {
                    Log.e(TAG, "失败的目录: ${failedDirectories.joinToString(", ")}")
                }
                
                if (completedDirectories == totalDirectories) {
                    Log.d(TAG, "所有资源下载完成")
                    callback.onComplete()
                } else {
                    val errorMsg = "部分资源下载失败: ${failedDirectories.size}/$totalDirectories 个目录失败"
                    Log.e(TAG, errorMsg)
                    callback.onError(errorMsg)
                }
                
            } catch (e: Exception) {
                Log.e(TAG, "下载过程出错", e)
                callback.onError(e.message ?: "下载失败")
            }
        }
    }
    
    /**
     * 递归下载整个目录
     */
    private suspend fun downloadDirectory(directoryName: String): Boolean {
        return withContext(Dispatchers.IO) {
            try {
                Log.d(TAG, "获取目录文件列表: $directoryName")
                // 获取目录下的所有文件列表
                val fileList = getDirectoryFileList(directoryName)
                if (fileList.isEmpty()) {
                    Log.w(TAG, "目录为空或获取文件列表失败: $directoryName")
                    return@withContext false
                }
                
                var successCount = 0
                val totalFiles = fileList.size
                val failedFiles = mutableListOf<String>()
                
                Log.d(TAG, "开始下载目录: $directoryName (共 $totalFiles 个文件)")
                Log.d(TAG, "文件列表: ${fileList.take(5).joinToString(", ")}${if (fileList.size > 5) "..." else ""}")
                
                fileList.forEachIndexed { index, filePath ->
                    try {
                        Log.d(TAG, "下载文件 ($index+1/$totalFiles): $filePath")
                        val success = downloadSingleFile(filePath)
                        if (success) {
                            successCount++
                            Log.d(TAG, "文件下载成功: $filePath")
                        } else {
                            failedFiles.add(filePath)
                            Log.e(TAG, "文件下载失败: $filePath")
                        }
                    } catch (e: Exception) {
                        failedFiles.add(filePath)
                        Log.e(TAG, "下载文件异常: $filePath", e)
                    }
                }
                
                val success = successCount == totalFiles
                Log.d(TAG, "目录下载完成: $directoryName ($successCount/$totalFiles)")
                if (failedFiles.isNotEmpty()) {
                    Log.e(TAG, "失败的文件: ${failedFiles.take(10).joinToString(", ")}${if (failedFiles.size > 10) "..." else ""}")
                }
                success
                
            } catch (e: Exception) {
                Log.e(TAG, "下载目录异常: $directoryName", e)
                false
            }
        }
    }
    
    /**
     * 获取目录下的所有文件列表
     */
    private suspend fun getDirectoryFileList(directoryName: String): List<String> {
        return withContext(Dispatchers.IO) {
            try {
                val url = URL("$BASE_URL/api/directory/$directoryName")
                Log.d(TAG, "请求目录文件列表: $url")
                
                val connection = url.openConnection() as HttpURLConnection
                connection.requestMethod = "GET"
                connection.connectTimeout = 10000
                connection.readTimeout = 15000
                connection.setRequestProperty("Accept", "application/json")
                
                val responseCode = connection.responseCode
                Log.d(TAG, "目录API响应码: $responseCode")
                
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    val inputStream = connection.inputStream
                    val content = inputStream.bufferedReader().use { it.readText() }
                    inputStream.close()
                    connection.disconnect()
                    
                    Log.d(TAG, "目录API响应内容长度: ${content.length}")
                    
                    // 解析JSON响应
                    val fileList = parseFileListFromJson(content, directoryName)
                    Log.d(TAG, "解析到文件数量: ${fileList.size}")
                    fileList
                } else {
                    Log.e(TAG, "获取目录列表失败，响应码: $responseCode, 目录: $directoryName")
                    emptyList()
                }
            } catch (e: Exception) {
                Log.e(TAG, "获取目录文件列表异常: $directoryName", e)
                emptyList()
            }
        }
    }
    
    /**
     * 从JSON响应中解析文件列表
     */
    private fun parseFileListFromJson(jsonContent: String, directoryName: String): List<String> {
        return try {
            val jsonObject = org.json.JSONObject(jsonContent)
            val filesArray = jsonObject.getJSONArray("files")
            val fileList = mutableListOf<String>()
            
            for (i in 0 until filesArray.length()) {
                val fileObject = filesArray.getJSONObject(i)
                val filePath = fileObject.getString("path")
                fileList.add("$directoryName/$filePath")
            }
            
            Log.d(TAG, "解析到 ${fileList.size} 个文件: $directoryName")
            fileList
        } catch (e: Exception) {
            Log.e(TAG, "解析文件列表JSON失败: $directoryName", e)
            emptyList()
        }
    }
    
    /**
     * 下载单个文件
     */
    private suspend fun downloadSingleFile(filePath: String): Boolean {
        return withContext(Dispatchers.IO) {
            try {
                val url = URL("$BASE_URL/$filePath")
                Log.d(TAG, "下载文件: $url")
                
                val connection = url.openConnection() as HttpURLConnection
                connection.requestMethod = "GET"
                connection.connectTimeout = 10000
                connection.readTimeout = 15000
                
                val responseCode = connection.responseCode
                Log.d(TAG, "文件响应码: $responseCode, 文件: $filePath")
                
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    val inputStream = connection.inputStream
                    val localFile = File(cacheDir, filePath)
                    
                    // 确保目录存在
                    val parentDir = localFile.parentFile
                    if (parentDir != null && !parentDir.exists()) {
                        val created = parentDir.mkdirs()
                        Log.d(TAG, "创建目录: ${parentDir.absolutePath}, 成功: $created")
                    }
                    
                    val outputStream = FileOutputStream(localFile)
                    val bytesCopied = inputStream.copyTo(outputStream)
                    
                    inputStream.close()
                    outputStream.close()
                    connection.disconnect()
                    
                    Log.d(TAG, "文件下载成功: $filePath, 大小: $bytesCopied 字节")
                    true
                } else {
                    Log.e(TAG, "下载文件失败，响应码: $responseCode, 文件: $filePath")
                    false
                }
            } catch (e: Exception) {
                Log.e(TAG, "下载文件异常: $filePath", e)
                false
            }
        }
    }
    
    /**
     * 下载单个资源
     */
    private suspend fun downloadResource(key: String, path: String): Boolean {
        return withContext(Dispatchers.IO) {
            try {
                val url = URL("$BASE_URL$path")
                val connection = url.openConnection() as HttpURLConnection
                connection.requestMethod = "GET"
                connection.connectTimeout = 15000
                connection.readTimeout = 30000
                
                val responseCode = connection.responseCode
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    val inputStream = connection.inputStream
                    val file = File(cacheDir, path)
                    
                    // 确保目录存在
                    file.parentFile?.mkdirs()
                    
                    val outputStream = FileOutputStream(file)
                    val buffer = ByteArray(8192)
                    var bytesRead: Int
                    
                    while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                        outputStream.write(buffer, 0, bytesRead)
                    }
                    
                    outputStream.close()
                    inputStream.close()
                    connection.disconnect()
                    
                    Log.d(TAG, "资源下载成功: $key")
                    true
                } else {
                    Log.e(TAG, "下载失败，响应码: $responseCode")
                    false
                }
            } catch (e: Exception) {
                Log.e(TAG, "下载资源异常: $key", e)
                false
            }
        }
    }
    
    /**
     * 获取本地资源路径
     */
    fun getLocalResourcePath(originalPath: String): String {
        return try {
            // 处理相对路径，去掉开头的 ./
            val cleanPath = originalPath.removePrefix("./")
            
            // 将 html/ 路径映射到实际的下载目录
            val mappedPath = if (cleanPath.startsWith("html/")) {
                cleanPath.replace("html/", "")
            } else {
                cleanPath
            }
            
            // 构建本地文件路径
            val localFile = File(cacheDir, mappedPath)
            
            if (localFile.exists()) {
                val fileUrl = "file://${localFile.absolutePath}"
                Log.d(TAG, "找到本地文件: $originalPath -> $fileUrl")
                fileUrl
            } else { 
                // 如果本地文件不存在，返回原始路径（让WebView尝试从网络加载）
                Log.w(TAG, "本地文件不存在: $originalPath -> $mappedPath (${localFile.absolutePath})")
                originalPath
            }
        } catch (e: Exception) {
            Log.e(TAG, "获取本地资源路径失败: $originalPath", e)
            originalPath
        }
    }
    
    /**
     * 检查资源是否已下载
     */
    fun isResourceDownloaded(originalPath: String): Boolean {
        val localPath = originalPath.replace("./html/", "")
        val file = File(cacheDir, localPath)
        return file.exists()
    }
    
    /**
     * 获取所有已下载的资源
     */
    fun getDownloadedResources(): List<String> {
        return resourceDirectories.filter { directoryName ->
            val mainHtmlPath = mainHtmlFiles[directoryName]
            if (mainHtmlPath != null) {
                isResourceDownloaded("./html/$mainHtmlPath")
            } else {
                false
            }
        }
    }
    
    /**
     * 清理缓存
     */
    fun clearCache() {
        try {
            if (cacheDir.exists()) {
                cacheDir.deleteRecursively()
                cacheDir.mkdirs()
            }
        } catch (e: Exception) {
            Log.e(TAG, "清理缓存失败", e)
        }
    }
    
    /**
     * 获取缓存大小
     */
    fun getCacheSize(): Long {
        return if (cacheDir.exists()) {
            cacheDir.walkTopDown().sumOf { it.length() }
        } else {
            0L
        }
    }
    
    fun destroy() {
        downloadScope.cancel()
    }
}
